﻿using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PRC_Bot
{
    public partial class Form1 : Form
    {

        #region Global

        IWebDriver driver;
        Stopwatch sw;

        string url = "https://prcdice.eu/";
        string lastBetID;
        string lastBetTime;

        double initialBetAmount = 0.00000001;
        double chanceValue = 40;
        double currentAux;
        double balanceValue;
        double betMultiplierValue = 2;
        double maxPayoutValue;
        double betPayoutValue;

        int hiLoChangeValue = 20;
        int delayValue = 2500;
        int betCount;
        int errorCount;
        int winCount;
        int loseCount;
        int maxLosesValue;
        int worstStreak;
        int currentStreak;

        bool betting; 

        #endregion

        public Form1()
        {
            Application.ApplicationExit += new EventHandler(this.OnApplicationExit);

            // Start driver
//            Console.WriteLine("Starting Driver...");
            driver = new FirefoxDriver();

            // Open URL
//            Console.WriteLine("Loading " + url + "...");
            driver.Navigate().GoToUrl(url);

            Thread.Sleep(3000);

            InitializeComponent();

            currency.SelectedIndex = 0;
            startingBet.Text = initialBetAmount.ToString("N10", CultureInfo.InvariantCulture);
            chance.Text = chanceValue.ToString();
            multiplier.Text = betMultiplierValue.ToString();
            hiLoChange.Text = hiLoChangeValue.ToString();
            delay.Text = delayValue.ToString();

            username.Enabled = true;
            password.Enabled = true;
            loginButton.Enabled = true;
        }

        #region Bot Functions

        private bool Login(string user, string password)
        {
            // Go to login page
//            Console.WriteLine("Loggin in...");
            driver.FindElement(By.Id("LoginButton")).Click();
            Thread.Sleep(2000);

            // Set username and password
            IWebElement u = driver.FindElement(By.Id("UserName"));
            u.Clear();
            u.SendKeys(user);
            IWebElement p = driver.FindElement(By.Id("Password"));
            p.Clear();
            p.SendKeys(password);

            // Log in
            driver.FindElement(By.CssSelector("input.btn.btn-primary")).Click();
            Thread.Sleep(3000);

            // Check if we are logged in
            if (IsElementPresent(By.Id("AccountButton")))
            {
//                Console.WriteLine("Logged as " + user);
                return true;
            }
            else
            {
//                Console.WriteLine("Error!");
                return false;
            }
        }

        private void startBetting()
        {

            sw = Stopwatch.StartNew();
            Thread.Sleep(500);

            // Start Betting
            double currentBetAmount = initialBetAmount;

            try
            {
                lastBetID = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td")).Text;
                lastBetTime = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td[3]")).Text;
            }
            catch (Exception)
            {
                lastBetID = "000";
                lastBetTime = "00:00";
            }

//            Console.WriteLine("Last Bet ID: " + lastBetID);

            // Aux
            bool hi_lo = true;
            int hi_loCounter = 1;
            string profitAux = "";
            double profitAux2 = 0;

            betting = true;

            while (betting)
            {
                // Place Bet
                if (Bet(currentBetAmount, hi_lo))
                {
                    errorCount = 0;
                    profitAux = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td[8]")).Text;

                    // Check Win/Lose bet
                    if (profitAux.Contains("-"))
                    {
                        currentBetAmount = currentBetAmount * betMultiplierValue;
                        loseCount++;
                        currentStreak++;
                    }
                    else
                    {
                        currentBetAmount = initialBetAmount;
                        winCount++;
                        currentStreak = 0;
                    }

                    // Update profit
                    try
                    {
                        profitAux2 = double.Parse(profitAux.Substring(0, profitAux.Length - 2), NumberStyles.Number, CultureInfo.InvariantCulture);
                        currentAux = currentAux + profitAux2;
                    }
                    catch (Exception)
                    {
                        throw;
                    }

                    // Change Hi/Lo Bet
                    hi_loCounter++;
                    if (hi_loCounter > hiLoChangeValue)
                    {
                        hi_loCounter = 1;
                        hi_lo = !hi_lo;
                    }

//                    Console.WriteLine("  #################  " + currentAux.ToString("N2") + "  #################");

                    betCount++;

                }
                else
                {
                    errorCount++;
//                    Console.WriteLine("  #################  error in bet(" + errorCount + ")  #################");
                    //error = true;
                }

                this.Invoke((MethodInvoker)delegate
                {

                    try
                    {
                        totalBets.Text = betCount.ToString() + " (" + (betCount / ((double)sw.ElapsedMilliseconds / 60000f)).ToString("N1") + " bets/min)";
                    }
                    catch (Exception)
                    {
                        totalBets.Text = betCount.ToString() + " (0 bets/min)";
                    }

                    currentBet.Text = lastBetID + "  " + lastBetTime;
                    errors.Text = errorCount.ToString();

                    string balanceAux = driver.FindElement(By.CssSelector("td.myBalance")).Text;
                    string maxPayoutAux = driver.FindElement(By.CssSelector("span.diceMaxBet")).Text;

                    balanceValue = double.Parse(balanceAux.Substring(0, balanceAux.Length - 2), NumberStyles.Number, CultureInfo.InvariantCulture);
                    maxPayoutValue = double.Parse(maxPayoutAux.Substring(0, maxPayoutAux.Length - 2), NumberStyles.Number, CultureInfo.InvariantCulture);

                    if (Regex.IsMatch(balanceAux, "^[\\s\\S]*D$"))
                    {
                        prcBalance.Text = balanceValue.ToString("N2") + " D";
                        try
                        {
                            currentProfit.Text = currentAux.ToString("N2") + " D (" + (currentAux / ((double)sw.ElapsedMilliseconds / 3600000f)).ToString("N2") + " D/h)";
                        }
                        catch (Exception)
                        {
                            currentProfit.Text = currentAux.ToString("N2") + " D (0 D/h)";
                        }
                        maxPayout.Text = maxPayoutValue.ToString("N2") + " D";
                    }
                    else
                    {
                        prcBalance.Text = balanceValue.ToString("N8") + " B";
                        try
                        {
                            currentProfit.Text = currentAux.ToString("N8") + " B (" + (currentAux / (sw.ElapsedMilliseconds / 3600000)).ToString("N6") + " B/h)";
                        }
                        catch (Exception)
                        {
                            currentProfit.Text = currentAux.ToString("N8") + " B (0 B/h)";
                        }
                        maxPayout.Text = maxPayoutValue.ToString("N8") + " B";
                    }

                    if (currentAux > 0)
                    {
                        currentProfit.ForeColor = Color.Green;
                    }
                    else
                    {
                        currentProfit.ForeColor = Color.Red;
                    }
                    
                    double currentLuck = winCount / ((betCount * chanceValue) / 100);

                    if (currentLuck >= 1)
                    {
                        luck.ForeColor = Color.Green;
                    }
                    else
                    {
                        luck.ForeColor = Color.Red;
                    }

                    luck.Text = winCount + "/" + loseCount + " (" + currentLuck.ToString("N2") + ")";

                    if (currentStreak > worstStreak)
                    {
                        worstStreak = currentStreak;
                        worstLoseStreak.Text = worstStreak.ToString();
                    }

                    time.Text = sw.Elapsed.ToString(@"d\.hh\:mm\:ss");

                });

                Thread.Sleep(delayValue);
            }
        }

        private bool Bet(double amount, bool hi_lo)
        {
            // Set Bet Amount
            driver.FindElement(By.Id("diceBetAmount")).Clear();
            driver.FindElement(By.Id("diceBetAmount")).SendKeys(amount.ToString("N10", CultureInfo.InvariantCulture));

            // Place Bet
            if (hi_lo)
            {
                driver.FindElement(By.Id("diceLobby")).SendKeys("h");
            }
            else
            {
                driver.FindElement(By.Id("diceLobby")).SendKeys("l");
            }

            Thread.Sleep(1000);

            // Check if bet was placed correctly
            string currentBetID = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td")).Text;
            if (lastBetID.Equals(currentBetID))
            {
                // Bet not placed, try one more time
                Thread.Sleep(2000);
                currentBetID = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td")).Text;
                if (lastBetID.Equals(currentBetID))
                {
                    return false;
                }
                else
                {
                    lastBetID = currentBetID;
                    lastBetTime = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td[3]")).Text;
                    return true;
                }
            }
            else
            {
                // Bet placed, update lastBetID
                lastBetID = currentBetID;
                lastBetTime = driver.FindElement(By.XPath("//div[@id='tmyDiceBets']/div/table/tbody/tr/td[3]")).Text;
                return true;
            }
        }

        private string updateBalance()
        {

            try
            {
                string currencyAux = driver.FindElement(By.CssSelector("td.myBalance")).Text;
                string maxPayoutAux = driver.FindElement(By.CssSelector("span.diceMaxBet")).Text;
                balanceValue = double.Parse(currencyAux.Substring(0, currencyAux.Length - 2), NumberStyles.Number, CultureInfo.InvariantCulture);
                maxPayoutValue = double.Parse(maxPayoutAux.Substring(0, maxPayoutAux.Length - 2), NumberStyles.Number, CultureInfo.InvariantCulture);
                return currencyAux;
            }
            catch (Exception)
            {

                balanceValue = 0;
                maxPayoutValue = 0;
                return "";
            }
            

        }

        private void calculateMaxBets()
        {

            updateBalance();
            double posibleProfit = 0;
            double currBalance = balanceValue;
            double currBet = initialBetAmount;
            int count = 0;

            if (currBalance > 0 && initialBetAmount > 0 && betMultiplierValue > 0 && betPayoutValue > 0)
            {
                while (posibleProfit < maxPayoutValue || currBalance > 0)
                {
                    currBet = (initialBetAmount * (double)(Math.Pow(betMultiplierValue, count)));
                    currBalance = currBalance - currBet;
                    posibleProfit = currBet * betPayoutValue;
                    count++;
                }
            }
            else
            {
                count = 0;
            }

            maxLosesValue = count;
            maxLoses.Text = maxLosesValue.ToString();
        } 

        #endregion

        #region Aux Functions

        private void blockUI(bool block)
        {
            if (block)
            {
                currency.Enabled = false;
                startingBet.Enabled = false;
                chance.Enabled = false;
                hiLoChange.Enabled = false;
                delay.Enabled = false;

                startButton.Enabled = false;
                stopButton.Enabled = false;
                resetButton.Enabled = false;
            }
            else
            {
                currency.Enabled = true;
                startingBet.Enabled = true;
                chance.Enabled = true;
                hiLoChange.Enabled = true;
                delay.Enabled = true;

                startButton.Enabled = true;
                stopButton.Enabled = true;
                resetButton.Enabled = true;
            }
        }

        private bool IsElementPresent(By by)
        {
            try
            {
                driver.FindElement(by);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }

        private void OnApplicationExit(object sender, EventArgs e)
        {
            driver.Quit();
        } 

        #endregion

        #region Select Changed

        private void currency_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Change currency
//            blockUI(true);
            ComboBox comboBox = (ComboBox)sender;
            string currencyString = (string)comboBox.SelectedItem;

            new SelectElement(driver.FindElement(By.Id("diceCurrencyValue"))).SelectByText(currencyString);

            bool currencyChanged = false;
            double seconds = 0;
            while (!currencyChanged)
            {
                if (seconds >= 5)
                {
//                    Console.WriteLine("ERROR CHANGING CURRENCY!");
                    Application.Exit();
                }

                Thread.Sleep(500);
                seconds = seconds + 0.5f;

                string saux = updateBalance();

                if (currencyString.Equals("Dogecoin") && Regex.IsMatch(saux, "^[\\s\\S]*D$"))
                {
                    currencyChanged = true;
                    prcBalance.Text = balanceValue.ToString("N2");
                    maxPayout.Text = maxPayoutValue.ToString("N2");
                }
                else
                {
                    currencyChanged = true;
                    prcBalance.Text = balanceValue.ToString("N6");
                    maxPayout.Text = maxPayoutValue.ToString("N6");
                }
                
            }

            //blockUI(false);
//            Console.WriteLine("Changed currency to " + currencyString + "...");
        } 
        #endregion

        #region TextBox Changed

        private void startingBet_TextChanged(object sender, EventArgs e)
        {

            // Console.WriteLine("Setting bet amount...");
            driver.FindElement(By.Id("diceBetAmount")).Clear();
            driver.FindElement(By.Id("diceBetAmount")).SendKeys(startingBet.Text);
            try
            {
                initialBetAmount = double.Parse(startingBet.Text, NumberStyles.Number, CultureInfo.InvariantCulture);
                calculateMaxBets();
            }
            catch
            {
                initialBetAmount = 0;
            }
        }

        private void chance_TextChanged(object sender, EventArgs e)
        {
            // Set Chance
            TextBox textBox = (TextBox)sender;
//            Console.WriteLine("Setting chance...");
            driver.FindElement(By.Id("diceChance")).Clear();
            driver.FindElement(By.Id("diceChance")).SendKeys(textBox.Text);
            try
            {
                chanceValue = double.Parse(textBox.Text);
                betPayoutValue = double.Parse(driver.FindElement(By.Id("dicePayout")).GetAttribute("value"));
                calculateMaxBets();
            }
            catch
            {
                chanceValue = 0;
                betPayoutValue = 0;
            }

        }

        private void multiplier_TextChanged(object sender, EventArgs e)
        {
            // Set Bet Multiplier
            TextBox textBox = (TextBox)sender;
//            Console.WriteLine("Setting bet Multiplier...");
            try
            {
                betMultiplierValue = double.Parse(multiplier.Text, NumberStyles.Number, CultureInfo.InvariantCulture);
                calculateMaxBets();
            }
            catch (Exception)
            {

                betMultiplierValue = 0;
            }

        }

        private void hiLoChange_TextChanged(object sender, EventArgs e)
        {
            try
            {
                hiLoChangeValue = int.Parse(((TextBox)sender).Text);
            }
            catch (Exception)
            {

                hiLoChangeValue = 1;
            }
        }

        private void delay_TextChanged(object sender, EventArgs e)
        {

            try
            {
                delayValue = int.Parse(((TextBox)sender).Text);
            }
            catch (Exception)
            {
                delayValue = 3000;
            }

        }

        #endregion

        #region Button Click

        private void login_Click(object sender, EventArgs e)
        {
            if(username.Text.Length>0 && password.Text.Length>0)
            {
                loginButton.Enabled = false;
                button1.Enabled = false;

                if (!Login(username.Text, password.Text))
                {
                    // Console.WriteLine("LOGIN ERROR!");
                    driver.Navigate().GoToUrl(url);
                    Thread.Sleep(2000);
                    loginButton.Enabled = true;
                    button1.Enabled = true;
                }
                else
                {
                    // Console.WriteLine("Showing my last bets...");
                    driver.FindElement(By.LinkText("My Bets")).Click();

                    // Console.WriteLine("Enabling shortcuts...");
                    driver.FindElement(By.XPath("//div[@id='diceLobby']/div/div/div/table/tbody/tr/td/button")).Click();

                    username.Enabled = false;
                    password.Enabled = false;
                    loginButton.Enabled = false;

                    startingBet.Text = initialBetAmount.ToString("N10", CultureInfo.InvariantCulture);
                    chance.Text = chanceValue.ToString();
                    multiplier.Text = betMultiplierValue.ToString();
                    hiLoChange.Text = hiLoChangeValue.ToString();
                    delay.Text = delayValue.ToString();

                    calculateMaxBets();

                    currency.Enabled = true;
                    startingBet.Enabled = true;
                    chance.Enabled = true;
                    multiplier.Enabled = true;
                    hiLoChange.Enabled = true;
                    delay.Enabled = true;
                    startButton.Enabled = true;
                }
            }
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            startButton.Enabled = false;
            Thread bettingBot = new Thread(new ThreadStart(startBetting));
            bettingBot.Start();
            while (!bettingBot.IsAlive) ;
            stopButton.Enabled = true;
            resetButton.Enabled = true;
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            stopButton.Enabled = false;
            betting = false;
            try
            {
                sw.Stop();
            }
            catch (Exception)
            {
                ;
            }
            startButton.Enabled = true;
        }

        private void resetButton_Click(object sender, EventArgs e)
        {
            betCount = 0;
            totalBets.Text = "-";
            currentAux = 0;
            currentProfit.Text = "-";
            errorCount = 0;
            errors.Text = "-";
            winCount = 0;
            loseCount = 0;
            luck.Text = "-";
            currentStreak = 0;
            worstStreak = 0;
            worstLoseStreak.Text = "-";
            maxLoses.Text = "-";
            maxPayout.Text = "-";
            time.Text = "00:00:00";
            try
            {
                sw.Reset();
            }
            catch (Exception)
            {
                ;
            }
        }

        private void reload_Click_1(object sender, EventArgs e)
        {
            button1.Enabled = false;
//            Console.WriteLine("Loading " + url + "...");
            driver.Navigate().GoToUrl(url);
            Thread.Sleep(3000);
            button1.Enabled = true;
        } 

        #endregion

        private void label24_Click(object sender, EventArgs e)
        {

        }

        private void label21_Click(object sender, EventArgs e)
        {

        }

        private void password_KeyPress(object sender, KeyPressEventArgs e)
        {
            if(e.KeyChar ==  (char)13)
            {
                login_Click(null, null);
            }
        }
        
    }
}
